package com.platform.qujia.pay.strategy.payment;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.platform.qujia.config.BasicInfo;
import com.platform.qujia.constantEnum.TianQuetechPayEnum;
import com.platform.qujia.controller.QuJiaPayV2Controller;
import com.platform.qujia.dao.PayOrderMapper;
import com.platform.qujia.enums.PayTypeEnum;
import com.platform.qujia.param.request.AddPayOrderParam;
import com.platform.qujia.param.request.TradeReverseScanPayParameter;
import com.platform.qujia.pay.PaymentStrategy;
import com.platform.qujia.pojo.PayOrder;
import com.platform.qujia.pojo.PayWay;
import com.platform.qujia.pojo.TradeReversePayInfo;
import com.platform.qujia.pojo.dto.DivideAccountsSettingDto;
import com.platform.qujia.service.NotifyService;
import com.platform.qujia.service.TradePaymentRecordsService;
import com.platform.qujia.utils.ApiRequestBean;
import com.platform.qujia.utils.CodeMsg;
import com.platform.qujia.utils.RSASignature;
import com.platform.qujia.utils.exception.CustomException;
import com.yunhua.oil.common.core.utils.SpringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * @date 2023/8/11
 */
@Component
public class SXFPayment implements PaymentStrategy {

    private static final Logger log = LoggerFactory.getLogger(SXFPayment.class);

    @Autowired
    private TradePaymentRecordsService tradePaymentRecordsService;
    @Resource
    private PayOrderMapper payOrderMapper;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private NotifyService notifyService;
    @Value("${domain.payName}${server.servlet.context-path}/sxfPayCallbackV2")
    private String sxfNotifyUrl;
    @Autowired
    private QuJiaPayV2Controller quJiaPayV2Controller;

    @Override
    public Object beforePay(AddPayOrderParam orderParam, PayOrder payOrder, PayWay payWay) {
        orderParam.setOrgId(BasicInfo.TRADE_REVERSE_PAY_ORGID);
        if(tradePaymentRecordsService.addTradePaymentRecords(orderParam,payOrder.getOrderNo())<=0) {
            throw new CustomException("创建支付日志失败");
        }
        TradeReverseScanPayParameter param=new TradeReverseScanPayParameter();
        BeanUtil.copyProperties(orderParam, param);
        param.setAmt(String.valueOf(payOrder.getAmt()));
        if (StringUtils.isNotBlank(payOrder.getCustomerPhone())) {
            param.setNotifyUrl(sxfNotifyUrl);
            param.setExtend(PayTypeEnum.pos.getType());
        }
        param.setOrdNo(payOrder.getOrderNo());
        return param;
    }

    @Override
    public Object doPay(AddPayOrderParam orderParam, PayOrder payOrder,PayWay payWay, Object preParam) {
        TradeReverseScanPayParameter param = (TradeReverseScanPayParameter) preParam;
        ApiRequestBean<JSONObject> reqBean = new ApiRequestBean<JSONObject>();
        log.info("随行支付-被动扫码开始"+param.getOrdNo());
        reqBean.setSignType("RSA");
        reqBean.setVersion("1.0");
        JSONObject reqData = (JSONObject) JSONObject.toJSON(param);
        reqBean.setReqData(reqData);
        reqBean.setOrgId(param.getOrgId());
        reqBean.setReqId(param.getReqId());
        reqBean.setTimestamp(param.getTimestamp());
        //业务参数
        reqData.put("mno", param.getMno()); //商户编号
        if (StringUtils.isNotBlank(param.getNotifyUrl())) {
            reqData.put("notifyUrl", param.getNotifyUrl()); //回调地址
        }else{
            reqData.put("notifyUrl", BasicInfo.PAY_NAMEURL+BasicInfo.TRADE_REVERSE_PAY_NOTIFYURL); //回调地址
        }

        if (orderParam != null && orderParam.isPay()) {
            List<DivideAccountsSettingDto> divideAccList = payOrderMapper.selectDivideSettingDetail(param.getMno(),payOrder.getStationId().toString());
            if(divideAccList.size()>0 && divideAccList.get(0).getBeginMmo()!=null){
                reqData.put("ledgerAccountFlag", "00"); //是否做分账 分账交易使 用；00：做； 01：不做；不传默认为不做分账
                reqData.put("ledgerAccountEffectTime", "01"); //分账有效时间 单位为天；是 否做分账选择 00 时该字段必传
            }
        }

        reqData.put("ordNo", param.getOrdNo()); //商户订单号
        reqData.put("authCode", param.getAuthCode()); //授权码
        reqData.put("amt", param.getAmt()); //订单总金额
        reqData.put("subject", param.getSubject()); //订单标题
        reqData.put("trmIp", param.getTrmIp());
        reqBean.setReqData(reqData);
        String req = JSONObject.toJSONString(reqBean);
        //此处不要改变reqData里面值的顺序用LinkedHashMap
        @SuppressWarnings("unchecked")
        HashMap<String, Object> reqMap = JSON.parseObject(req, LinkedHashMap.class, Feature.OrderedField);
        //组装加密串
        String signContent = RSASignature.getOrderContent(reqMap);
        try {
            String sign = RSASignature.encryptBASE64(RSASignature.sign(signContent, BasicInfo.TRADE_REVERSE_PAY_PRIVATEKEY));
            reqMap.put("sign", sign);
            //log.debug("请求参数reqMap:" + reqMap);
            log.info("随行付扫码支付请求参数reqStr:{}",JSON.toJSONString(reqMap));
            //String resultJson = HttpUtils.connectPostUrl(BasicInfo.TRADE_REVERSE_PAY_TIANQUEURL+BasicInfo.TRADE_REVERSE_PAY_REVERSESCANURL, reqStr);
            ResponseEntity<String> res = restTemplate.postForEntity(BasicInfo.TRADE_REVERSE_PAY_TIANQUEURL + BasicInfo.TRADE_REVERSE_PAY_REVERSESCANURL, reqMap, String.class);
            String resultJson = res.getBody();
            //不要对reqData排序 所以用LinkedHashMap
            log.info("随行付扫码支付返回结果:{}",resultJson);

            @SuppressWarnings("unchecked")
            HashMap<String, Object> resultMap = JSON.parseObject(resultJson, LinkedHashMap.class, Feature.OrderedField);
            if ("0000".equals(resultMap.get("code"))) {
                JSONObject jsobject=new JSONObject(resultMap);
                String string = jsobject.getString("respData");
                return JSON.parseObject(string, TradeReversePayInfo.class);
            }
        } catch (Exception e) {
            log.error(e.getMessage(),e);
        }
        return null;
    }

    @Override
    public boolean checkResult(PayOrder payOrder, Object result) {
        if (result == null) {
            return false;
        }
        TradeReversePayInfo info = (TradeReversePayInfo) result;
        if (StringUtils.equalsAny(info.getBizCode(),"0000","2002")) {
            return true;
        }
        throw new CustomException(info.getBizMsg());
    }


    @Override
    public boolean checkResult2(PayOrder payOrder, Object result) {
        if (result == null) {
            return false;
        }
        TradeReversePayInfo info = (TradeReversePayInfo) result;
        if (StringUtils.equals(info.getBizCode(),"0000")) {
            return true;
        }
        if (StringUtils.equals(info.getBizCode(),"2002")){
            throw new CustomException(CodeMsg.TRADE_REVERSE_PAY_WAIT_MINUTE);
        }
        throw new CustomException(info.getBizMsg());
    }

    @Override
    public TianQuetechPayEnum checkResult3(PayOrder payOrder, Object result) {
        if (result == null) {
            return TianQuetechPayEnum.PAY_FAIL;
        }
        TradeReversePayInfo info = (TradeReversePayInfo) result;
        if (StringUtils.equals(info.getBizCode(),"0000")) {
            return TianQuetechPayEnum.PAY_SUCCESS;
        }
        if (StringUtils.equals(info.getBizCode(),"2002")){
            return TianQuetechPayEnum.PAY_PAYING;
        }
        return TianQuetechPayEnum.PAY_FAIL;
    }

    @Override
    public void postPay(PayOrder payOrder, Object result) {
        if (result == null) {
            return;
        }
        TradeReversePayInfo info = (TradeReversePayInfo) result;
        tradePaymentRecordsService.updateTradeReversePayInfo(info);

    }

    @Override
    public void syncPostPay(PayOrder payOrder, Object result) {
        TradeReversePayInfo info = (TradeReversePayInfo) result;
        if (StringUtils.equals("0000",info.getBizCode())) {
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
            Date paydate = null;
            try {
                paydate = format.parse(info.getPayTime());
            } catch (ParseException e) {
                log.error(e.getMessage(),e);
            }
            final Date pd;
            if (paydate != null) {
                pd = paydate;
            }else{
                pd = new Date();
            }
            SXFPayment bean = SpringUtils.getBean(SXFPayment.class);
            if (StringUtils.isNotBlank(payOrder.getCustomerPhone())) {
                bean.asyncCallbackWithUser(payOrder.getOrderNo(),info);
            }else{
                bean.asyncCallbackWithoutUser(payOrder.getOrderNo(),info.getOrdNo(),pd);
            }
        }
    }

    @Async
    @Transactional
    public void asyncCallbackWithoutUser(String orderNo,String ordSn,Date payDate){
        log.info("POS机随行付同步回调,orderNo:[{}],ordSn:[{}]",orderNo,ordSn);
        notifyService.updateTradeReverseOrder(orderNo, payDate);
    }

    @Async
    public void asyncCallbackWithUser(String orderNo,TradeReversePayInfo info){
        log.info("POS机随行付同步回调,orderNo:[{}],ordSn:[{}]",orderNo,info.getOrdNo());
        quJiaPayV2Controller.sxfPayOrderCallback(info.getPayTime(),orderNo,info.getOriTranAmt(),info.getTransactionId(),info.getSettleAmt(),info.getPayType(), PayTypeEnum.pos.getType());
    }
}
